// a
const protobuffik::float_32 a( -0.1f );

// b
const protobuffik::uint_64 b( 123456 );

// c
const protobuffik::fixed_string< > c( "c" );

// d
const protobuffik::fixed_string< 16 > d( "d" );

enum ChunkType
{
    CHUNK_TYPE_FILE_ATTRIBUTES = 1,

    CHUNK_TYPE_INDEX = 2,

    CHUNK_TYPE_KEY_VALUE = 3,

    CHUNK_TYPE_TEST_1 = 4,

    CHUNK_TYPE_REMOVE_KEY = 4,

    CHUNK_TYPE_TEST_2 = 5
};

// MAGIC_NUMBER
const protobuffik::uint_64 MAGIC_NUMBER( 50988526717644704 );

// MAGIC_NUMBER2
const protobuffik::uint_64 MAGIC_NUMBER2( 2216409480638853224 );

class Test
{
public:
    Test( )
        : testInt( 10 )
        , testString( c )
        , testFixedString( d )
    {
    }

    size_t save( protobuffik::ostream& out ) const
    {
        size_t bytesSaved = 0;

        protobuffik::uint_32 n = 3;
        bytesSaved += protobuffik::save( out, n );

        {
            filed_name_type fieldName( "testInt" );
            bytesSaved += protobuffik::save( out, fieldName );
            bytesSaved += protobuffik::save( out, testInt );
        }

        {
            filed_name_type fieldName( "testString" );
            bytesSaved += protobuffik::save( out, fieldName );
            bytesSaved += protobuffik::save( out, testString );
        }

        {
            filed_name_type fieldName( "testFixedString" );
            bytesSaved += protobuffik::save( out, fieldName );
            bytesSaved += protobuffik::save( out, testFixedString );
        }

        return bytesSaved;
    }

    size_t load( protobuffik::istream& in )
    {
        size_t bytesLoaded = 0;

        protobuffik::uint_32 n = 0;
        {
            size_t ss = 0;

            protobuffik::LoadingResult r = protobuffik::load( in, n, ss );
            if( r != protobuffik::LOADING_RESULT_OK )
                return r;

            bytesLoaded += ss;
        }

        for( protobuffik::uint_32 i = 0; i < n; ++i )
        {
            filed_name_type fieldName;
            {
                size_t ss = 0;

                protobuffik::LoadingResult r = protobuffik::load( in, fieldName, ss );
                if( r != protobuffik::LOADING_RESULT_OK )
                    return r;

                bytesLoaded += ss;
            }
            
            if( fieldName == "testInt" )
            {
                size_t ss = 0;

                protobuffik::LoadingResult r = protobuffik::load( in, testInt, ss );
                if( r != protobuffik::LOADING_RESULT_OK )
                    return r;

                bytesLoaded += ss;
            }
            
            if( fieldName == "testString" )
            {
                size_t ss = 0;

                protobuffik::LoadingResult r = protobuffik::load( in, testString, ss );
                if( r != protobuffik::LOADING_RESULT_OK )
                    return r;

                bytesLoaded += ss;
            }
            
            if( fieldName == "testFixedString" )
            {
                size_t ss = 0;

                protobuffik::LoadingResult r = protobuffik::load( in, testFixedString, ss );
                if( r != protobuffik::LOADING_RESULT_OK )
                    return r;

                bytesLoaded += ss;
            }
        }

        return bytesLoaded;
    }

private:
    typedef protobuffik::fixed_string< 128 > filed_name_type;

public:
    protobuffik::uint_64 testInt;
    protobuffik::fixed_string< > testString;
    protobuffik::fixed_string< 64 > testFixedString;
};

class TestTest
{
public:
    TestTest( )
        : v( 10 )
        , v2( 20 )
        , v3( 20 )
    {
    }

    size_t save( protobuffik::ostream& out ) const
    {
        size_t bytesSaved = 0;

        protobuffik::uint_32 n = 4;
        bytesSaved += protobuffik::save( out, n );

        {
            filed_name_type fieldName( "v" );
            bytesSaved += protobuffik::save( out, fieldName );
            bytesSaved += protobuffik::save( out, v );
        }

        {
            filed_name_type fieldName( "v2" );
            bytesSaved += protobuffik::save( out, fieldName );
            bytesSaved += protobuffik::save( out, v2 );
        }

        {
            filed_name_type fieldName( "v3" );
            bytesSaved += protobuffik::save( out, fieldName );
            bytesSaved += protobuffik::save( out, v3 );
        }

        {
            filed_name_type fieldName( "t" );
            bytesSaved += protobuffik::save( out, fieldName );
            bytesSaved += protobuffik::save( out, t );
        }

        return bytesSaved;
    }

    size_t load( protobuffik::istream& in )
    {
        size_t bytesLoaded = 0;

        protobuffik::uint_32 n = 0;
        {
            size_t ss = 0;

            protobuffik::LoadingResult r = protobuffik::load( in, n, ss );
            if( r != protobuffik::LOADING_RESULT_OK )
                return r;

            bytesLoaded += ss;
        }

        for( protobuffik::uint_32 i = 0; i < n; ++i )
        {
            filed_name_type fieldName;
            {
                size_t ss = 0;

                protobuffik::LoadingResult r = protobuffik::load( in, fieldName, ss );
                if( r != protobuffik::LOADING_RESULT_OK )
                    return r;

                bytesLoaded += ss;
            }
            
            if( fieldName == "v" )
            {
                size_t ss = 0;

                protobuffik::LoadingResult r = protobuffik::load( in, v, ss );
                if( r != protobuffik::LOADING_RESULT_OK )
                    return r;

                bytesLoaded += ss;
            }
            
            if( fieldName == "v2" )
            {
                size_t ss = 0;

                protobuffik::LoadingResult r = protobuffik::load( in, v2, ss );
                if( r != protobuffik::LOADING_RESULT_OK )
                    return r;

                bytesLoaded += ss;
            }
            
            if( fieldName == "v3" )
            {
                size_t ss = 0;

                protobuffik::LoadingResult r = protobuffik::load( in, v3, ss );
                if( r != protobuffik::LOADING_RESULT_OK )
                    return r;

                bytesLoaded += ss;
            }
            
            if( fieldName == "t" )
            {
                size_t ss = 0;

                protobuffik::LoadingResult r = protobuffik::load( in, t, ss );
                if( r != protobuffik::LOADING_RESULT_OK )
                    return r;

                bytesLoaded += ss;
            }
        }

        return bytesLoaded;
    }

private:
    typedef protobuffik::fixed_string< 128 > filed_name_type;

public:
    protobuffik::uint_64 v;
    protobuffik::uint_64 v2;
    protobuffik::uint_64 v3;
    Test t;
};